import { join } from 'path';
import { TempFileConfig, TempFileInfo } from '../types';
import { FileUtil } from './fileUtil';

/**
 * 临时文件管理器
 * 用于管理未保存的文件内容，支持宕机恢复和自动清理
 */
export class TempFileManager {
    /** 临时文件管理器配置 */
    private config: TempFileConfig;
    /** 临时文件元数据文件路径 */
    private metadataPath: string;

    /**
     * 创建临时文件管理器实例
     * @param config 配置信息，包含临时文件目录和过期时间
     */
    constructor(config: TempFileConfig) {
        this.config = config;
        this.metadataPath = join(config.tempDir, 'temp_metadata.json');
    }

    /**
     * 初始化临时文件管理器
     * - 创建临时文件目录
     * - 初始化元数据文件
     * - 清理过期的临时文件
     */
    async initialize(): Promise<void> {
        await FileUtil.createDirectory(this.config.tempDir);
        if (!await FileUtil.exists(this.metadataPath)) {
            await FileUtil.writeFile(this.metadataPath, JSON.stringify([]));
        }
        await this.cleanupExpired();
    }

    /**
     * 生成临时文件ID
     * 格式：temp_时间戳_随机数，例如：temp_1705662094000_1234
     * - 时间戳确保基本的唯一性
     * - 随机数解决同一毫秒内的冲突
     * - temp_前缀便于识别
     */
    private generateTempId(): string {
        const timestamp = Date.now();
        const random = Math.floor(Math.random() * 10000);
        return `temp_${timestamp}_${random}`;
    }

    /**
     * 创建临时文件
     * @param targetName 目标文件名，最终要创建的文件名
     * @param parentId 父目录ID，不提供则创建在根目录
     * @param content 初始文件内容，默认为空字符串
     * @returns 临时文件信息，包含ID和元数据
     */
    async createTemp(targetName: string, parentId?: string, content: string = ''): Promise<TempFileInfo> {
        const tempInfo: TempFileInfo = {
            id: this.generateTempId(),
            targetName,
            parentId,
            createTime: Date.now(),
            lastModified: Date.now(),
            saved: false
        };

        // 保存临时文件内容
        const tempPath = this.getTempPath(tempInfo.id);
        await FileUtil.writeFile(tempPath, content);

        // 更新元数据
        const metadata = await this.getMetadata();
        metadata.push(tempInfo);
        await this.saveMetadata(metadata);

        return tempInfo;
    }

    /**
     * 更新临时文件内容
     * @param tempId 临时文件ID
     * @param content 新的文件内容
     * @returns 是否更新成功
     */
    async updateTemp(tempId: string, content: string): Promise<boolean> {
        const metadata = await this.getMetadata();
        const tempInfo = metadata.find(t => t.id === tempId);

        if (!tempInfo) {
            return false;
        }

        // 更新内容
        const tempPath = this.getTempPath(tempId);
        await FileUtil.writeFile(tempPath, content);

        // 更新元数据
        tempInfo.lastModified = Date.now();
        await this.saveMetadata(metadata);

        return true;
    }

    /**
     * 获取临时文件内容
     * @param tempId 临时文件ID
     * @returns 文件内容，如果文件不存在则返回null
     */
    async getTempContent(tempId: string): Promise<string | null> {
        const tempPath = this.getTempPath(tempId);
        if (!await FileUtil.exists(tempPath)) {
            return null;
        }
        return await FileUtil.readFile(tempPath);
    }

    /**
     * 标记临时文件为已保存
     * 当临时文件成功保存为正式文件后调用
     * @param tempId 临时文件ID
     * @returns 是否标记成功
     */
    async markAsSaved(tempId: string): Promise<boolean> {
        const metadata = await this.getMetadata();
        const tempInfo = metadata.find(t => t.id === tempId);

        if (!tempInfo) {
            return false;
        }

        tempInfo.saved = true;
        await this.saveMetadata(metadata);
        return true;
    }

    /**
     * 删除临时文件
     * 同时删除文件内容和元数据
     * @param tempId 临时文件ID
     * @returns 是否删除成功
     */
    async deleteTemp(tempId: string): Promise<boolean> {
        const tempPath = this.getTempPath(tempId);
        if (await FileUtil.exists(tempPath)) {
            await FileUtil.delete(tempPath);
        }

        const metadata = await this.getMetadata();
        const index = metadata.findIndex(t => t.id === tempId);
        if (index !== -1) {
            metadata.splice(index, 1);
            await this.saveMetadata(metadata);
            return true;
        }
        return false;
    }

    /**
     * 获取未保存的临时文件列表
     * 用于系统启动时检查是否有未保存的文件需要恢复
     * @returns 未保存的临时文件信息列表
     */
    async getUnsavedFiles(): Promise<TempFileInfo[]> {
        const metadata = await this.getMetadata();
        return metadata.filter(t => !t.saved);
    }

    /**
     * 获取临时文件元数据
     * @returns 所有临时文件的元数据列表
     */
    public async getMetadata(): Promise<TempFileInfo[]> {
        const content = await FileUtil.readFile(this.metadataPath);
        return JSON.parse(content);
    }

    /**
     * 保存临时文件元数据
     * @param metadata 要保存的元数据列表
     */
    private async saveMetadata(metadata: TempFileInfo[]): Promise<void> {
        await FileUtil.writeFile(this.metadataPath, JSON.stringify(metadata));
    }

    /**
     * 获取临时文件的实际存储路径
     * @param tempId 临时文件ID
     * @returns 完整的文件系统路径
     */
    private getTempPath(tempId: string): string {
        return join(this.config.tempDir, `${tempId}.tmp`);
    }

    /**
     * 清理过期的临时文件
     * - 删除超过过期时间的文件
     * - 删除已保存的临时文件
     * - 同时清理文件内容和元数据
     */
    private async cleanupExpired(): Promise<void> {
        const metadata = await this.getMetadata();
        const now = Date.now();
        const validFiles = metadata.filter(temp => {
            const age = now - temp.lastModified;
            if (age > this.config.expireTime || temp.saved) {
                // 删除过期或已保存的临时文件
                const tempPath = this.getTempPath(temp.id);
                FileUtil.delete(tempPath).catch(() => {});
                return false;
            }
            return true;
        });

        if (validFiles.length !== metadata.length) {
            await this.saveMetadata(validFiles);
        }
    }
}
